﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.Xaml;
using com.IronOne.BoardPACWinAppBO.Comment;
using com.IronOne.BoardPACWinAppBO.General;
using com.IronOne.BoardPACWinAppBO.Sync;
using com.IronOne.BoardPACWinAppService.Comment;
using com.IronOne.BoardPACWinAppUtil.Util;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Messaging;
using Windows.ApplicationModel.DataTransfer;

namespace com.IronOne.BoardPACWinApp.ViewModel
{
    /// <summary>
    ///     This class contains properties that a View can data bind to.
    ///     <para>
    ///         See http://www.galasoft.ch/mvvm
    ///     </para>
    /// </summary>
    public class CommentViewModel : ViewModelBase
    {
        public const string DistinctMeetingListPropertyName = "DistinctMeetingList";

        /// <summary>
        ///     The <see cref="SelectedCommentList" /> property's name.
        /// </summary>
        public const string SelectedCommentListPropertyName = "SelectedCommentList";

        /// <summary>
        ///     The <see cref="SelectedMeetingModel" /> property's name.
        /// </summary>
        public const string SelectedMeetingModelPropertyName = "SelectedMeetingModel";

        /// <summary>
        ///     The <see cref="SelectedIndex" /> property's name.
        /// </summary>
        public const string SelectedIndexPropertyName = "SelectedIndex";

        private ObservableCollection<CommentModel> _distinctMeetingList;
        private ObservableCollection<CommentModel> _selectedCommentList;
        private int _selectedIndex = -1;
        private CommentModel _selectedMeetingModel;
        //private readonly INavigationService _navigationService;
        //private readonly IDialogService _dialogService;
        private ObservableCollection<CommentModel> _commentModelList;
        private readonly ICommentService _commentService;
        private readonly DataTransferManager _dataTransferManager;
        string datetimeFormat = Utility.GetDateTimeFormat();

        /// <summary>
        ///     Initializes a new instance of the CommentViewModel class.
        /// </summary>
        public CommentViewModel()
        {
            try
            {
                _selectedCommentList = new ObservableCollection<CommentModel>();
                _commentService = new CommentService();
                _commentModelList = new ObservableCollection<CommentModel>();

                Messenger.Default.Register<NotificationMessage<MessageDataModel>>(this, HandleMessages);

                CommentModel.EmailCommentOnClick -= OnEmailCommentClick;
                CommentModel.EmailCommentOnClick = null;
                CommentModel.EmailCommentOnClick += OnEmailCommentClick;

                _dataTransferManager = DataTransferManager.GetForCurrentView();
                _dataTransferManager.DataRequested += DataRequested;

                GetAllComments();
            }
            catch (Exception)
            {
            }
        }

        CommentModel _globalSelectedCommentItem = null;
        private void OnEmailCommentClick(object sender, EventArgs e)
        {
            try
            {
                _globalSelectedCommentItem = sender as CommentModel;
                DataTransferManager.ShowShareUI();
            }
            catch (Exception)
            {
            }
        }

        private void DataRequested(DataTransferManager sender, DataRequestedEventArgs e)
        {
            try
            {
                var dataPackage = e.Request.Data;
                if (_globalSelectedCommentItem == null) return;
                var related = "";
                
                related = _globalSelectedCommentItem.CommentTypeName;
                dataPackage.Properties.Title = "Comment of " + related;

                dataPackage.Properties.Description = "Mail app is recommended for email";
                dataPackage.Properties.ApplicationName = "BoardPAC";
                dataPackage.SetHtmlFormat(
                    HtmlFormatHelper.CreateHtmlFormat(_globalSelectedCommentItem.Comment +
                                                      "<br/><br/><b>Related to:</b/><br/>" +
                                                      related +
                                                      "<br/><br/><b>Commented by:</b/><br/>" +
                                                      _globalSelectedCommentItem.CommentBy +
                                                      "<br/><br/><b>Date:</b/><br/>" +
                                                      _globalSelectedCommentItem.CommentDate.ToString(datetimeFormat)
                                                      ));
            }
            catch (Exception)
            {
            }
        }

        public ObservableCollection<CommentModel> CommentsList
        {
            get { return _commentModelList; }
            set
            {
                _commentModelList = value;
                RaisePropertyChanged("CommentsList");
            }
        }

        /// <summary>
        ///     Sets and gets the DistinctMeetingList property.
        ///     Changes to that property's value raise the PropertyChanged event.
        /// </summary>
        public ObservableCollection<CommentModel> DistinctMeetingList
        {
            get { return _distinctMeetingList; }

            set
            {
                _distinctMeetingList = value;
                RaisePropertyChanged(DistinctMeetingListPropertyName);
            }
        }

        /// <summary>
        ///     Sets and gets the SelectedCommentList property.
        ///     Changes to that property's value raise the PropertyChanged event.
        /// </summary>
        public ObservableCollection<CommentModel> SelectedCommentList
        {
            get { return _selectedCommentList; }

            set
            {
                if (_selectedCommentList == value)
                {
                    return;
                }
                _selectedCommentList = value;
                RaisePropertyChanged(SelectedCommentListPropertyName);
            }
        }

        public CommentModel SelectedMeetingModel
        {
            get { return _selectedMeetingModel; }

            set
            {
                if (_selectedMeetingModel == value)
                {
                    return;
                }

                _selectedMeetingModel = value;
                if (_selectedMeetingModel != null)
                {
                    GetMeetingWiseComments(_selectedMeetingModel.MeetingId);
                }
                RaisePropertyChanged(SelectedMeetingModelPropertyName);
            }
        }

        public int SelectedIndex
        {
            get { return _selectedIndex; }

            set
            {
                if (_selectedIndex == value)
                {
                    return;
                }

                _selectedIndex = value;

                if (_selectedIndex == -1) //Master view item deselected state-> Clear meeting detail view
                {
                    SelectedCommentList.Clear();
                }

                RaisePropertyChanged(SelectedIndexPropertyName);
            }
        }

        private async void HandleMessages(NotificationMessage<MessageDataModel> mdm)
        {
            if (!mdm.Notification.Equals(MessageCodes.SYNC_UPDATED_DATA)) return;
            try
            {
                var sudm = (SyncUpdatedDataModel) mdm.Content.MessageData;
                //TODO: Include category and subcategory as well
                if ((sudm.Comments == null || sudm.Comments.Count <= 0) &&
                    (sudm.Meetings == null || sudm.Meetings.Count <= 1)) return;
                if (_selectedMeetingModel == null) return;
                var selectedIndexBeforeSync = DistinctMeetingList.IndexOf(_selectedMeetingModel);
                //Set selected index after sync
                await
                    CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                        async () =>
                        {
                            CommentsList = await _commentService.GetAllComments();
                            GetDistinctMeetingListFromComments();
                            int? updatedMeetingId = DistinctMeetingList[selectedIndexBeforeSync].MeetingId;
                            GetMeetingWiseComments(updatedMeetingId);
                            SelectedIndex = selectedIndexBeforeSync;
                        });
            }
            catch (Exception)
            {
            }
        }

        public async Task GetAllComments()
        {
            try
            {
                IEnumerable<CommentModel> allComments = await _commentService.GetAllComments();
                _commentModelList = new ObservableCollection<CommentModel>(allComments);
                GetDistinctMeetingListFromComments();

                if (DistinctMeetingList != null && DistinctMeetingList.Count > 0)
                    SelectedIndex = 0;
            }
            catch (Exception)
            {
            }
        }

        public void GetDistinctMeetingListFromComments()
        {
            try
            {
                IEnumerable<CommentModel> distinctMeetingList = (from cl in _commentModelList
                    group cl by
                        new
                        {
                            cl.MeetingId,
                            cl.MeetingVenue,
                            cl.MeetingName,
                            cl.MainCategory,
                            cl.SubCategory,
                            cl.CommentCount,
                            cl.MeetingDate
                        }
                    into clGroup
                    select new CommentModel
                    {
                        MeetingId = clGroup.Key.MeetingId,
                        MeetingName = clGroup.Key.MeetingName,
                        MeetingVenue = clGroup.Key.MeetingVenue,
                        MainCategory = clGroup.Key.MainCategory,
                        SubCategory = clGroup.Key.SubCategory,
                        CommentCount = clGroup.Key.CommentCount,
                        MeetingDateString = Utility.GetDate(clGroup.Key.MeetingDate).ToString(Global.DateFormat)
                    }).ToList();

                DistinctMeetingList = new ObservableCollection<CommentModel>(distinctMeetingList);
            }
            catch (Exception)
            {
            }
        }

        public void GetMeetingWiseComments(int? meetingId)
        {
            try
            {
                IEnumerable<CommentModel> selectedComments = CommentsList.Where(c => c.MeetingId == meetingId).ToList();

                var finalCommentList = new List<CommentModel>();
                var meetingIds = new List<int>();
                var paperIds = new List<int>();

                #region MeetingComments

                IEnumerable<CommentModel> selectedMeetingComments =
                    selectedComments.Where(c => c.CommentType == 1).OrderByDescending(c => c.CommentDate).ToList();
                var firstMeetingComment = selectedMeetingComments.FirstOrDefault();

                const string path = "ms-appx:///Assets/Images/CommentsPage/";
                foreach (var item in selectedMeetingComments)
                {
                    if (item.Equals(firstMeetingComment))
                    {
                        var cm = new CommentModel
                        {
                            CommentHeadingVisibility = Visibility.Visible,
                            CommentTypeName = item.CommentTypeName
                        };
                        finalCommentList.Add(cm);
                    }

                    item.CommentByBackgroundColor = "#1785ba";
                    item.EmailBtnBgColor = "#01a4ef";
                    item.CommentDateString = Utility.GetDate(item.CommentDate).ToString(datetimeFormat);

                    if (item.MemberId == Global.UserId)
                    {
                        item.CommentRightVisibility = Visibility.Visible;
                        item.CommentArrowPath = path + "Comment_MeetingCommentRightArrow.png";
                        item.CommentBackgroundColor = "#f6fcff";
                    }

                    if (item.MemberId != Global.UserId)
                    {
                        item.CommentLeftVisibility = Visibility.Visible;
                        item.CommentArrowPath = path + "Comment_MeetingCommentLeftArrow.png";
                        item.CommentBackgroundColor = "#ebf9ff";
                    }

                    meetingIds.Add(item.MeetingId);
                    finalCommentList.Add(item);
                }

                #endregion

                #region PaperComments

                IEnumerable<CommentModel> selectedPaperComments =
                    selectedComments.Where(c => c.CommentType == 0).OrderByDescending(c => c.CommentDate).ToList();

                var disntinctPaperIds = selectedPaperComments.Select(a => a.PaperId).Distinct().ToList();

                foreach (var paperId in disntinctPaperIds)
                {
                    var paperWiseCommentList = selectedPaperComments.Where(p => p.PaperId == paperId).ToList();

                    var firstMeetingPaperComment = paperWiseCommentList.FirstOrDefault();

                    foreach (var item in paperWiseCommentList)
                    {
                        if (firstMeetingPaperComment.Equals(item))
                            //check first item of iteration, if first item add the heading
                        {
                            var cm = new CommentModel
                            {
                                CommentTypeName = item.CommentTypeName,
                                CommentHeadingVisibility = Visibility.Visible
                            };
                            finalCommentList.Add(cm);
                        }

                        item.CommentByBackgroundColor = "#6ac082";
                        item.EmailBtnBgColor = "#1f98a0";
                        item.CommentDateString = Utility.GetDate(item.CommentDate).ToString(datetimeFormat);

                        if (item.MemberId == Global.UserId)
                        {
                            item.CommentRightVisibility = Visibility.Visible;
                            item.CommentArrowPath = path + "Comment_PaperCommentRightArrow.png";
                            item.CommentBackgroundColor = "#effff3";
                        }

                        if (item.MemberId != Global.UserId)
                        {
                            item.CommentLeftVisibility = Visibility.Visible;
                            item.CommentArrowPath = path + "Comment_PaperCommentleftArrow.png";
                            item.CommentBackgroundColor = "#d8f5e0";
                        }
                        finalCommentList.Add(item);
                    }
                    paperIds.Add(paperId);
                }

                #endregion

                if (paperIds.Count > 0)
                {
                    _commentService.UpdateViewedComments(ApplicationConstants.LogActions.UpdateViewedPaperComments,
                        new List<int>(), paperIds);
                }
                if (meetingIds.Count > 0)
                {
                    _commentService.UpdateViewedComments(ApplicationConstants.LogActions.UpdateViewedMeetingComments,
                        meetingIds, new List<int>());
                }
                SelectedCommentList = new ObservableCollection<CommentModel>(finalCommentList);
            }
            catch (Exception)
            {
            }
        }
    }
}